/*
XPTracker - Alternative Agile Tracking Tool
Copyright (C) 2006-2009  Stephen Starkey

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/
package org.xptracker.search;

import junit.framework.TestCase;
import org.apache.lucene.document.Document;
import org.xptracker.domain.*;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author caliendo
 */
public class AnnotationDrivenIndexingHelperTest extends TestCase {

  private static final AnnotationDrivenIndexingHelper helper = new AnnotationDrivenIndexingHelper();

  /**
   * Tests that different objects are properly parsed for search indexing
   */
  @SearchedItem(idField="string")
  private static final class TestClass {
    @SearchField(queryField ="string", stored=true, description="")
    public static final String getString() { return "string"; }

    @SearchField(queryField ="null", stored=true, description="")
    public static final Object getNull() { return null; } 

    @SearchField(queryField ="user", stored=true, description="")
    public static final User getUser() { 
      final User user = new User("username");

      user.setFullName("fullName");
      user.setEmail("email");
      return user;
    }

    @SearchField(queryField ="date", stored=true, description="")
    public static final Date getDate() { return new Date(0); }

    @SearchField(queryField ="storyCategory", stored=true, description="")
    public static final StoryCategory getStoryCategory() { return new StoryCategory("storyCategory"); } 

    @SearchField(queryField ="customer", stored=true, description="")
    public static final Customer getCustomer() { return new Customer("customer"); }

    @SearchField(queryField ="effortEntry", stored=true, description="")
    public static final EffortEntry getEffortEntry() { return new EffortEntry(null, getUser(), new Date(0), new Date(0), ""); }

    @SearchField(queryField ="task", stored=true, description="")
    public static final Task getTask() { return new Task("task", "task", getUser()); }

    @SearchField(queryField ="blogEntry", stored=true, description="")
    public static final BlogEntry getBlogEntry() { return new BlogEntry(getUser(), new Story(), "blogEntry"); }

    @SearchField(queryField ="collection", stored=true, description="")
    public static final Collection<Object> getCollection() { return Arrays.asList(new Object[]{"collectionString", new StringBuilder("collectionBuilder"), getUser()}); }

    public static final String notSearchable() { throw new Error("should not be invoked!"); }
  }

  private void assertStringValue(final String fieldName, final String expectedValue, final Document doc) {
    assertEquals("expected stringValue to be certain value [" + fieldName + "]", expectedValue, doc.getField(fieldName).stringValue());
  }

  private void assertFieldPresent(final String fieldName, final Document doc) {
    assertNotNull("expected field in document [" + fieldName + "]", doc.getField(fieldName));
  }

  private void assertFieldNotPresent(final String fieldName, final Document doc) {
    assertNull("did not expect field in document [" + fieldName + "]", doc.getField(fieldName));
  }

  private void assertContains(final List<String> keywords, final String keyword) {
    assertTrue("expected field in document [" + keyword + "]", keywords.contains(keyword));
  }
  // -----
  // tests

  // -----

  public void testBuildDocument() throws Exception {
    final Document doc = helper.buildDocument(new TestClass());

    assertEquals("expected a certain number of fields in document", 10, Collections.list(doc.fields()).size());
    assertFieldPresent("doc.type", doc);
    assertFieldPresent("string", doc);
    assertFieldNotPresent("null", doc);
    assertFieldPresent("user", doc);
    assertFieldPresent("date", doc);
    assertFieldPresent("storyCategory", doc);
    assertFieldPresent("customer", doc);
    assertFieldPresent("effortEntry", doc);
    assertFieldPresent("task", doc);
    assertFieldPresent("blogEntry", doc);
    assertFieldPresent("collection", doc);

    assertStringValue("string", "string", doc);
    assertStringValue("user", "username fullName email", doc);
    assertStringValue("date", new SimpleDateFormat(AbstractIndexingHelper.DATE_PATTERN).format(new Date(0)), doc);
    assertStringValue("storyCategory", "storyCategory", doc);
    assertStringValue("customer", "customer", doc);
    assertStringValue("effortEntry", "username fullName email", doc);
    assertStringValue("task", "task task username fullName email", doc);
    assertStringValue("blogEntry", "blogEntry username fullName email", doc);
    assertStringValue("collection", "collectionString collectionBuilder username fullName email", doc);
  }

  public void testLoadQueryFields() throws Exception {
    final List<String> keywords = helper.loadQueryFields(TestClass.class);

    assertEquals("expected a certain number of keywords", 10, keywords.size());
    assertContains(keywords, "string");
    assertContains(keywords, "null");
    assertContains(keywords, "user");
    assertContains(keywords, "date");
    assertContains(keywords, "storyCategory");
    assertContains(keywords, "customer");
    assertContains(keywords, "effortEntry");
    assertContains(keywords, "task");
    assertContains(keywords, "blogEntry");
    assertContains(keywords, "collection");
  }

  public void testLoadQueryFieldsReturnsSameResultsForMultipleInvocations() throws Exception {
    final List<String> resultOne = helper.loadQueryFields(TestClass.class);
    final List<String> resultTwo = helper.loadQueryFields(TestClass.class);

    assertSame("expected methods to return same instance for multiple calls", resultOne, resultTwo);
  }

  public void testGetId() throws Exception {
    assertEquals("string", helper.getId(new TestClass()));
  }
}
